﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Data;

namespace sqlDALgen
{
    public class TemplateData : Dictionary<String, TemplateData>
    {
        public object Value { get; set; }

        public static TemplateData ValueNode(object value)
        {
            return new TemplateData { Value = value };
        }

        public override string ToString()
        {
            return (Value ?? String.Empty).ToString();
        }

        public TemplateData ResolvePath(string path)
        {
            var node = this;
            foreach (var item in path.Split('.'))
            {
                node = node[item];
            }
            return node;
        }

        public TemplateData TryResolvePath(string path)
        {
            var node = this;
            TemplateData retVal = null;
            foreach (var item in path.Split('.'))
            {
                if (node.ContainsKey(item))
                    node = node[item];
                else
                    return null;
            }
            retVal = node;
            return retVal;
        }

        public void RemovePath(string path)
        {
            var node = this;
            var items = path.Split('.');

            for (var i = 0; i < items.Length - 1; i++)
            {
                node = node[items[i]];
            }

            node.Remove(items[items.Length - 1]);
        }

        /// <summary>
        /// Load template data from xml file
        /// </summary>
        /// <param name="xmlFile"></param>
        /// <returns></returns>
        public static TemplateData FromXmlFile(String xmlFile)
        {
            var xmlDoc = new XmlDocument();
            xmlDoc.Load(xmlFile);

            return FromNode(xmlDoc.FirstChild);
        }

        /// <summary>
        /// Load template data from xml string
        /// </summary>
        /// <param name="xml"></param>
        /// <returns></returns>
        public static TemplateData FromXml(String xml)
        {
            var xmlDoc = new XmlDocument();
            xmlDoc.LoadXml(xml);

            return FromNode(xmlDoc.FirstChild);
        }

        private static TemplateData FromNode(XmlNode node)
        {
            var data = new TemplateData { { node.Name, new TemplateData() } };
            for (var i = 0; node.Attributes != null && i < node.Attributes.Count; i++)
            {
                data[node.Name].Add(node.Attributes[i].Name, TemplateData.ValueNode(node.Attributes[i].Value));
            }

            bool isTextNode = false;
            var nodes = new List<XmlNode>();
            foreach (XmlNode child in node.ChildNodes)
            {
                if (child.Name == "#text"
                    || child.Name == "#cdata-section")
                {
                    data[node.Name].Value = child.InnerText;
                    isTextNode = true;
                    break;
                }
                else
                    nodes.Add(child);
            }

            if (isTextNode) return data;

            var cnt = 0;
            var isItemsNode = false;
            foreach(var child in nodes)
            {
                if (data[node.Name].ContainsKey(child.Name))
                {
                    var zeroIdxData = data[node.Name][child.Name];
                    data[node.Name].Remove(child.Name);
                    data[node.Name].Add((cnt - 1).ToString(), zeroIdxData);

                    isItemsNode = true;
                }

                if (isItemsNode)
                    data.ResolvePath(node.Name).Add(cnt.ToString(), FromNode(child)[child.Name]);
                else
                    data.ResolvePath(node.Name).Add(child.Name, FromNode(child)[child.Name]);
                cnt++;
            }

            return data;
        }

        /// <summary>
        /// Load template data from DataSet
        /// </summary>
        /// <param name="def"></param>
        /// <returns></returns>
        public static TemplateData FromDataset(DataSet def)
        {
            var data = new TemplateData { { "tables", new TemplateData() } };

            for (var i = 0; i < def.Tables.Count; i++)
            {
                data["tables"].Add(i.ToString(), new TemplateData { { "items", new TemplateData() } });
                var items = data["tables"][i.ToString()]["items"];


                for (var j = 0; j < def.Tables[i].Rows.Count; j++)
                {
                    items.Add(j.ToString(), new TemplateData());
                    var item = items[j.ToString()];

                    for (var k = 0; k < def.Tables[i].Columns.Count; k++)
                    {
                        item.Add(def.Tables[i].Columns[k].ColumnName.ToLower(), TemplateData.ValueNode(def.Tables[i].Rows[j][def.Tables[i].Columns[k].ColumnName]));
                    }
                }
            }

            return data;
        }
    }
}
